

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/blog/img/fluid.png">
  <link rel="icon" href="/blog/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Solace">
  <meta name="keywords" content="">
  
    <meta name="description" content="欢迎收看js大型连续剧-第四集">
<meta property="og:type" content="article">
<meta property="og:title" content="JS红宝书第四章学习笔记">
<meta property="og:url" content="https://isolace.gitee.io/blog/2023/11/17/JS%E7%BA%A2%E5%AE%9D%E4%B9%A6%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/index.html">
<meta property="og:site_name" content="Solace的博客">
<meta property="og:description" content="欢迎收看js大型连续剧-第四集">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230824160640062.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831232900624.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234032078.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234111148.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230824160640062.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831232900624.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234032078.png">
<meta property="og:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234111148.png">
<meta property="article:published_time" content="2023-11-17T06:00:12.000Z">
<meta property="article:modified_time" content="2024-03-26T11:57:22.099Z">
<meta property="article:author" content="Solace">
<meta property="article:tag" content="Javascript">
<meta property="article:tag" content="红宝书">
<meta property="article:tag" content="web">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="c:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230824160640062.png">
  
  
    <meta name="referrer" content="no-referrer-when-downgrade">
  
  
  <title>JS红宝书第四章学习笔记 - Solace的博客</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/blog/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/blog/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/blog/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"isolace.gitee.io","root":"/blog/","version":"1.9.5-a","typing":{"enable":true,"typeSpeed":60,"cursorChar":"|","loop":false,"scope":["home"]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"left","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":null,"google":{"measurement_id":null},"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/blog/local-search.xml","include_content_in_search":true};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/blog/js/utils.js" ></script>
  <script  src="/blog/js/color-schema.js" ></script>
  

  

  
    <!-- Google tag (gtag.js) -->
    <script async>
      if (!Fluid.ctx.dnt) {
        Fluid.utils.createScript("https://www.googletagmanager.com/gtag/js?id=", function() {
          window.dataLayer = window.dataLayer || [];
          function gtag() {
            dataLayer.push(arguments);
          }
          gtag('js', new Date());
          gtag('config', '');
        });
      }
    </script>
  

  

  

  

  



  
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/blog/">
      <strong>Solace&#39;s Blog</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/archives/">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/tags/">
                <i class="iconfont icon-tags-fill"></i>
                <span>标签</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/blog/about/">
                <i class="iconfont icon-user-fill"></i>
                <span>关于</span>
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/blog/img/default.png') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle">JS红宝书第四章学习笔记</span>
          
        </div>

        
          
  <div class="mt-3">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-author" aria-hidden="true"></i>
        Solace
      </span>
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2023-11-17 14:00" pubdate>
          2023年11月17日 下午
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          12k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          98 分钟
        
      </span>
    

    
    
      
        <span id="busuanzi_container_page_pv" style="display: none">
          <i class="iconfont icon-eye" aria-hidden="true"></i>
          <span id="busuanzi_value_page_pv"></span> 次
        </span>
        
      
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="padding-left: 2rem; margin-right: -1rem">
    <div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <h1 id="seo-header">JS红宝书第四章学习笔记</h1>
            
            
              <div class="markdown-body">
                
                <h1 id="第四章-变量、作用域与内存"><a href="#第四章-变量、作用域与内存" class="headerlink" title="第四章 变量、作用域与内存"></a>第四章 变量、作用域与内存</h1><h2 id="4-1-原始值与引用值"><a href="#4-1-原始值与引用值" class="headerlink" title="4.1 原始值与引用值"></a>4.1 原始值与引用值</h2><p><strong>原始值：</strong>最简单的数据</p>
<p><strong>引用值：</strong>由多个值构成的对象，保存在内存中，<a href="#data-type1" id="data-type2">详见3.4</a></p>
<p>保存原始值的变量是按值访问的（by value），操作存储在变量中的实际值；</p>
<p>保存引用值的变量是按引用访问的（by reference），操作该对象的引用而非对象本身</p>
<h3 id="4-1-1-动态属性"><a href="#4-1-1-动态属性" class="headerlink" title="4.1.1 动态属性"></a>4.1.1 动态属性</h3><p>利用<code>new</code>创建对象并保存到变量中，可以为这个变量动态添加属性（引用值）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> person = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>person.<span class="hljs-property">name</span> = <span class="hljs-string">&quot;Solace&quot;</span>;<br>person.<span class="hljs-property">age</span> = <span class="hljs-number">19</span>;<br></code></pre></td></tr></table></figure>

<p>原始值不能有属性，只有引用值可以动态添加后面可以使用的属性</p>
<h3 id="4-1-2-复制值"><a href="#4-1-2-复制值" class="headerlink" title="4.1.2 复制值"></a>4.1.2 复制值</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> num1 = <span class="hljs-number">5</span>;<br><span class="hljs-keyword">let</span> num2 = num1;<br></code></pre></td></tr></table></figure>

<p>原始值复制赋值后两个变量相互独立，互不干扰；</p>
<p>引用值复制的是指针，指向堆内存的对象，两个变量指向同一个对象，改变时两个都变</p>
<img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230824160640062.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230824160640062" style="zoom:50%;" />

<h3 id="4-1-3-传递参数"><a href="#4-1-3-传递参数" class="headerlink" title="4.1.3 传递参数"></a>4.1.3 传递参数</h3><p>传参（包括对象）只有按值传递，变量有按值和按引用访问</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">setName</span>(<span class="hljs-params">obj</span>) &#123;<br> obj.<span class="hljs-property">name</span> = <span class="hljs-string">&quot;Nicholas&quot;</span>;<br>&#125;<br><span class="hljs-keyword">let</span> person = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br><span class="hljs-title function_">setName</span>(person);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(person.<span class="hljs-property">name</span>); <span class="hljs-comment">// &quot;Nicholas&quot;</span><br></code></pre></td></tr></table></figure>

<p>再函数内obj和person都指向同一个对象，即使对象是按值传递的obj也会按引用访问该对象</p>
<h3 id="4-1-4-确定类型"><a href="#4-1-4-确定类型" class="headerlink" title="4.1.4 确定类型"></a>4.1.4 确定类型</h3><p><code>typeof</code>用于原始值</p>
<p>对于引用值使用<code>instanceof</code></p>
<p>用于判断是否为给定引用类型（由其原型链决定，详见第八章）+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(person <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Object</span>); <span class="hljs-comment">// 变量person是Object吗？</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(colors <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>); <span class="hljs-comment">// 变量colors是Array吗？</span><br></code></pre></td></tr></table></figure>

<p>用<code>instanceof</code>检测原始值返回<code>false</code></p>
<h2 id="4-2-执行上下文与作用域"><a href="#4-2-执行上下文与作用域" class="headerlink" title="4.2 执行上下文与作用域"></a>4.2 执行上下文与作用域</h2><p>执行上下文主要有<strong>全局上下文</strong>和<strong>函数上下文</strong>两种（eval() 调用内部 存在第三种上下文，不常用）</p>
<h5 id="全局执行上下文："><a href="#全局执行上下文：" class="headerlink" title="全局执行上下文："></a>全局执行上下文：</h5><p>不在任何函数中的代码都位于全局执行上下文中。</p>
<p>它做了两件事：</p>
<ol>
<li>创建一个全局对象，在浏览器中这个全局对象就是 <code>window</code> 对象。</li>
<li>将 <code>this</code> 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。</li>
</ol>
<h5 id="函数执行上下文："><a href="#函数执行上下文：" class="headerlink" title="函数执行上下文："></a>函数执行上下文：</h5><p>每次调用函数时，都会为该函数创建一个新的执行上下文。并压入执行上下文栈，函数执行结束后从栈中弹出。</p>
<p>每个函数都拥有自己的执行上下文，但是<strong>只有在函数被调用的时候才会被创建</strong>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;aaaaa&quot;</span>;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">check</span>(<span class="hljs-params"></span>) &#123;<br>	<span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;bbbbb&quot;</span>;<br>	<span class="hljs-keyword">function</span> <span class="hljs-title function_">f</span>(<span class="hljs-params"></span>)&#123;<br>		<span class="hljs-keyword">return</span> a;<br>	&#125;<br>	<span class="hljs-keyword">return</span> f;<br>&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">check</span>()());<br><span class="hljs-comment">//global()入栈（全局）</span><br><span class="hljs-comment">//check()入栈</span><br><span class="hljs-comment">//check()出栈</span><br><span class="hljs-comment">//f()入栈</span><br><span class="hljs-comment">//f()出栈</span><br><span class="hljs-comment">//global()出栈</span><br></code></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;aaaaa&quot;</span>;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">check</span>(<span class="hljs-params"></span>) &#123;<br>	<span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;bbbbb&quot;</span>;<br>	<span class="hljs-keyword">function</span> <span class="hljs-title function_">f</span>(<span class="hljs-params"></span>)&#123;<br>		<span class="hljs-keyword">return</span> a;<br>	&#125;<br>	<span class="hljs-keyword">return</span> <span class="hljs-title function_">f</span>();<br>&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">check</span>());<br><span class="hljs-comment">//global()入栈（全局）</span><br><span class="hljs-comment">//check()入栈</span><br><span class="hljs-comment">//f()入栈</span><br><span class="hljs-comment">//f()出栈</span><br><span class="hljs-comment">//check()出栈</span><br><span class="hljs-comment">//global()出栈</span><br></code></pre></td></tr></table></figure>

<p>每个上下文都有一个关联的<strong>变量对象</strong>，而这个上下文中定义的所有变量和函数都存在于这个对象上。虽然无法通过代码访问变量对象，但后台处理数据会用到它。</p>
<p>上下文中的代码执行时会创建变量对象的一个<strong>作用域链</strong>，决定了各级上下文中的代码在访问<strong>变量和函数</strong>时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。如果上下文是函数，则其<strong>活动对象</strong>用作变量对象。 活动对象最初只有一个定义变量：arguments 。（全局上下文中没有这个变量。）作用域链中的下一个变量对象来自包含上下文，再下一个对象来自再下一个包含上下文。以此类推直至全局上下文；全局上下文的变量 对象始终是作用域链的最后一个变量对象</p>
<blockquote>
<p>ithink</p>
<p>通过作用域链，JavaScript 引擎可以在当前函数无法找到变量或函数时，依次向上级的变量对象查找，直到找到或者达到全局执行上下文的变量对象。</p>
<p>具体来说，一个函数的变量对象会包含以下内容：</p>
<ol>
<li>函数内部声明的变量，包括通过 <code>var</code>、<code>let</code>、<code>const</code> 声明的变量。</li>
<li>函数声明，即通过函数表达式或函数声明方式定义的函数。</li>
<li>对于非全局函数来说，它的变量对象还会包含指向父级函数的变量对象的引用，以构建作用域链。</li>
</ol>
</blockquote>
<h3 id="4-2-1-作用域链增强"><a href="#4-2-1-作用域链增强" class="headerlink" title="4.2.1 作用域链增强"></a>4.2.1 作用域链增强</h3><p>某些语句会导致在作用域链前端临时添加一个上下文，这个上下文在代码执行后会被删除。</p>
<ul>
<li><code>try / catch</code>的 <code>catch</code> 块：创建一 个新的变量对象，包含要抛出的错误对象的声明</li>
<li><code>with</code>语句：向作用域链前端添加指定的对象</li>
</ul>
<h3 id="4-2-2-变量声明"><a href="#4-2-2-变量声明" class="headerlink" title="4.2.2 变量声明"></a>4.2.2 变量声明</h3><h5 id="01-使用var-的函数作用域声明"><a href="#01-使用var-的函数作用域声明" class="headerlink" title="01. 使用var 的函数作用域声明"></a>01. 使用var 的函数作用域声明</h5><p>使用var 声明变量时，变量会被自动添加到最接近的上下文</p>
<p>变量未经声明就被初始化，会自动被添加到<strong>全局上下文</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">num1, num2</span>) &#123;<br>    <span class="hljs-keyword">var</span> sum = num1 + num2;<br>    <span class="hljs-keyword">return</span> sum;<br>&#125;<br><span class="hljs-keyword">let</span> result = <span class="hljs-title function_">add</span>(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>); <span class="hljs-comment">// 30</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sum); <span class="hljs-comment">// 报错：sum在这里不是有效变量</span><br></code></pre></td></tr></table></figure>

<p>不对sum进行声明后</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">num1, num2</span>) &#123;<br>	sum = num1 + num2;<br>	<span class="hljs-keyword">return</span> sum;<br>&#125;<br><span class="hljs-keyword">let</span> result = <span class="hljs-title function_">add</span>(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>); <span class="hljs-comment">// 30</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sum); <span class="hljs-comment">// 30，这里sum为全局</span><br></code></pre></td></tr></table></figure>

<p>变量声明提升，但赋值等不变</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name); <span class="hljs-comment">// undefined</span><br><span class="hljs-keyword">var</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br><br><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>	<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name); <span class="hljs-comment">// undefined</span><br>	<span class="hljs-keyword">var</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<h5 id="02-使用let-的块级作用域声明"><a href="#02-使用let-的块级作用域声明" class="headerlink" title="02. 使用let 的块级作用域声明"></a>02. 使用let 的块级作用域声明</h5><p>单独的块是<code>let</code>声明的作用域；</p>
<p>同一变量名在同一作用域内不能声明两次；</p>
<p><code>var</code>声明的迭代变量会泄露到循环外部，<code>let</code>不会</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; ++i) &#123;&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i); <span class="hljs-comment">// 10</span><br><br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j &lt; <span class="hljs-number">10</span>; ++j) &#123;&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(j); <span class="hljs-comment">// ReferenceError: j没有定义</span><br></code></pre></td></tr></table></figure>

<h5 id="03-使用const-的常量声明"><a href="#03-使用const-的常量声明" class="headerlink" title="03. 使用const 的常量声明"></a>03. 使用const 的常量声明</h5><p>声明的同时必须初始化；</p>
<p>声明后在其生命周期不能重新赋值，其他同<code>let</code></p>
<p>赋值为对象的 const 变量不能再被重新赋值为其他引用值，但对象的键则不受限制（可以被修改）。</p>
<p><code>Object.freeze()</code>：使整个对象都不能被修改，再给属性赋值时虽然不会报错，但会静默失败：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> o3 = <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">freeze</span>(&#123;&#125;);<br>o3.<span class="hljs-property">name</span> = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(o3.<span class="hljs-property">name</span>); <span class="hljs-comment">// undefined</span><br></code></pre></td></tr></table></figure>

<h5 id="04-标识符查找"><a href="#04-标识符查找" class="headerlink" title="04. 标识符查找"></a>04. 标识符查找</h5><p>在特定上下文中为了读取或写入而引入一个标识符时，需要在作用域链查找搜索，搜索开始于作用域链前端，搜索给定名称。找到则确定变量，没有找到则沿作用域链查找</p>
<h2 id="4-3-垃圾回收"><a href="#4-3-垃圾回收" class="headerlink" title="4.3 垃圾回收"></a>4.3 垃圾回收</h2><p>js的执行环境在代码执行时管理内存；</p>
<p><strong>基本思路：</strong>确定哪个变量不会再使用，然后释放它所占用的内存。（周期性：垃圾回收程序每隔一段时间，或在代码执行过程中某个预定的收集时间，就会自动运行）</p>
<p>以函数中局部变量的生命周期为例：</p>
<p>函数执行时，堆（或栈）内存分配空间用于保存相应值，函数在内部使用该变量后退出，此时不再需要这个局部变量，可以释放其占用的内存。</p>
<p>垃圾回收程序跟踪记录哪个变量是否还会使用，以便回收内存</p>
<p>主要两种方法标记未使用的变量：<strong>标记清理</strong>和<strong>引用计数</strong></p>
<h3 id="4-3-1-标记清理"><a href="#4-3-1-标记清理" class="headerlink" title="4.3.1 标记清理"></a>4.3.1 标记清理</h3><p>最常用</p>
<p>变量进入上下文（如在函数内部声明一个变量）时，这个变量会被加上存在于上下文中的标记。当变量离开上下文时，也会被加上离开上下文的标记。</p>
<p>垃圾回收程序运行时：</p>
<ol>
<li>标记内存中存储的所有变量</li>
<li>去掉所有<code>在上下文中的变量</code>和<code>在上下文中的变量引用的变量</code>的标记</li>
<li>被标记的变量就是待删除变量，销毁带有标记的所有值并收回其内存</li>
</ol>
<p>标记方式：</p>
<ul>
<li>当变量进入上下文时，反转某一位；</li>
<li>维护«<code>在上下文中</code>»和«<code>不在上下文中</code>»两个变量列表，可以把变量从一个列表转移到另一个列表。</li>
</ul>
<h3 id="4-3-2-引用计数"><a href="#4-3-2-引用计数" class="headerlink" title="4.3.2 引用计数"></a>4.3.2 引用计数</h3><p><strong>思路：</strong>对每个值都记录他被引用的次数，声明变量并赋一个引用值时，该引用值的引用数加一；如果保存对该值引用的变量被其他值覆盖则引用数减一。当一个值的引用数为零时就说明没办法在访问该引用值，可以回收该值的内存。垃圾回收程序下次运行时会释放引用数为零的值的内存</p>
<p><strong>问题：</strong>循环引用</p>
<p>例一：对象A和对象B各有一个指针指向对象B和对象A，A和B通过各自的属性互相引用，引用数都是2。多次调用则有大量内存不会被释放。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">problem</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-keyword">let</span> objectA = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>    <span class="hljs-keyword">let</span> objectB = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>    objectA.<span class="hljs-property">someOtherObject</span> = objectB;<br>    objectB.<span class="hljs-property">anotherObject</span> = objectA;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>例二：在IE8以及更早的IE中，并非所有的对象都是js原生对象。BOM和DOM中的对象是C++实现的组件对象模型（COM） 对象，而COM对象使用<strong>引用计数</strong>实现垃圾回收。即使IE的 JavaScript引擎使用<strong>标记清理</strong>，JavaScript存取的COM对象依旧使用引用计数。也就是说，只要涉及COM对象，就无法避开循环引用问题。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> element = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">&quot;some_element&quot;</span>);<br><span class="hljs-keyword">let</span> myObject = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>myObject.<span class="hljs-property">element</span> = element;<br>element.<span class="hljs-property">someObject</span> = myObject;<br></code></pre></td></tr></table></figure>

<p>DOM对象和原生js对象发生循环引用，导致即使DOM元素已经被从页面中删除，其内存也不会被回收</p>
<p>解决：确保不使用时切断原生js对象和DOM元素之间的连接</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js">myObject.<span class="hljs-property">element</span> = <span class="hljs-literal">null</span>;<br>element.<span class="hljs-property">someObject</span> = <span class="hljs-literal">null</span>;<br></code></pre></td></tr></table></figure>

<h3 id="4-3-3-性能"><a href="#4-3-3-性能" class="headerlink" title="4.3.3 性能"></a>4.3.3 性能</h3><p>垃圾回收有可能会明显拖慢渲染的速度和帧速率</p>
<p>IE6机制：根据分配数，如分配了256个变量、4096个对象&#x2F;数组字面量和数组槽位（slot），或64KB字符串。满足其中某个条件垃圾回收程序就会运行。</p>
<p>IE7机制：动态改变触发垃圾回收的阈值，起始阈值与IE6相同，如果回收的内存不到已分配的15%则阈值翻倍；如果有一次的回收内存达到已分配的85%则重置阈值为默认值。</p>
<h3 id="4-3-4-内存管理"><a href="#4-3-4-内存管理" class="headerlink" title="4.3.4 内存管理"></a>4.3.4 内存管理</h3><p>将内存占用量保持在一个较小的值使页面性能更好（优化内存），数据不在必要时设置为<code>null</code>从而释放引用：<strong>解除引用</strong></p>
<blockquote>
<ul>
<li><p>最适合全局变量和全局对象的属性</p>
<p>局部变量在超出作用域后会自动解除引用</p>
</li>
<li><p>解除引用并不会自动导致相关内存被回收。</p>
<p>解除引用的关键在于确保相关的值已经不在上下文里了，在下次垃圾回 收时会被回收。</p>
</li>
</ul>
</blockquote>
<h5 id="01-通过const-和let-声明提升性能"><a href="#01-通过const-和let-声明提升性能" class="headerlink" title="01. 通过const 和let 声明提升性能"></a>01. 通过const 和let 声明提升性能</h5><p>都以块为作用域而不是函数，可能会更早地让垃圾回收程序介入，尽早回收</p>
<h5 id="02-隐藏类和删除操作"><a href="#02-隐藏类和删除操作" class="headerlink" title="02. 隐藏类和删除操作"></a>02. 隐藏类和删除操作</h5><p><img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831232900624.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230831232900624"></p>
<p><img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234032078.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230831234032078"></p>
<p><img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234111148.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230831234111148"></p>
<h5 id="03-内存泄露"><a href="#03-内存泄露" class="headerlink" title="03. 内存泄露"></a>03. 内存泄露</h5><p><strong>问题一</strong>：意外声明全局变量，未给变量利用<code>var</code>，<code>let</code>，<code>const</code>声明会被默认当做<code>window</code>属性来创建</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">setName</span>(<span class="hljs-params"></span>) &#123;<br> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br>&#125;<br><span class="hljs-comment">//相当于window.name = &#x27;Jake&#x27;</span><br></code></pre></td></tr></table></figure>

<p>解决：加上声明</p>
<p><strong>问题二</strong>：定时器</p>
<p>例中定时器的回调通过闭包引用了外部变量</p>
<p>只要定时器一直运行，回调函数中引用的name 就会一直占用内存。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br><span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> &#123;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name);<br>&#125;, <span class="hljs-number">100</span>);<br></code></pre></td></tr></table></figure>

<p><strong>问题三：</strong>闭包</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> outer = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-keyword">let</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>    	<span class="hljs-keyword">return</span> name;<br>    &#125;;<br>&#125;;<br></code></pre></td></tr></table></figure>

<p>调用<code>outer()</code>会导致分配给name的内存被泄漏，只要返回的函数存在就不能清理name ，因为闭包一直在引用着它</p>
<h5 id="04-静态分配与对象池"><a href="#04-静态分配与对象池" class="headerlink" title="04. 静态分配与对象池"></a>04. 静态分配与对象池</h5><p>为了提升性能，应当减少浏览器执行垃圾回收的次数 $\to$ 合理使用分配的内存，同时避免多余的垃圾回收，可以保住因释放内存而损失的性能</p>
<p>浏览器决定何时运行垃圾回收程序的一个标准就是对象更替的速度</p>
<p>例：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">addVector</span>(<span class="hljs-params">a, b</span>) &#123;<br>    <span class="hljs-keyword">let</span> resultant = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Vector</span>();<br>    resultant.<span class="hljs-property">x</span> = a.<span class="hljs-property">x</span> + b.<span class="hljs-property">x</span>;<br>    resultant.<span class="hljs-property">y</span> = a.<span class="hljs-property">y</span> + b.<span class="hljs-property">y</span>;<br>    <span class="hljs-keyword">return</span> resultant;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>如果矢量对象的生命周期很短 $\to$ 很快会成为可以被回收的值，如果频繁调用函数 $\to$ 垃圾回收程序会发现这里对象更替速度很快 $\to$ 更频繁的安排垃圾回收</p>
<p>解决：不使用动态创建对象，比如将对象通过传参传入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">addVector</span>(<span class="hljs-params">a, b, resultant</span>) &#123;<br>    resultant.<span class="hljs-property">x</span> = a.<span class="hljs-property">x</span> + b.<span class="hljs-property">x</span>;<br>    resultant.<span class="hljs-property">y</span> = a.<span class="hljs-property">y</span> + b.<span class="hljs-property">y</span>;<br>    <span class="hljs-keyword">return</span> resultant;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>在<strong>对象池</strong>中创建对象可以不让垃圾回收程序盯上，用于管理一组可回收的对象。</p>
<p>程序可以向对象池请求一个对象并设置属性，在使用结束后还给对象池</p>
<p>由于没有对象初始化，垃圾回收程序不会发现对象更替，减少垃圾回收程序执行频率# 第四章 变量、作用域与内存</p>
<h2 id="4-1-原始值与引用值-1"><a href="#4-1-原始值与引用值-1" class="headerlink" title="4.1 原始值与引用值"></a>4.1 原始值与引用值</h2><p><strong>原始值：</strong>最简单的数据</p>
<p><strong>引用值：</strong>由多个值构成的对象，保存在内存中，<a href="#data-type1" id="data-type2">详见3.4</a></p>
<p>保存原始值的变量是按值访问的（by value），操作存储在变量中的实际值；</p>
<p>保存引用值的变量是按引用访问的（by reference），操作该对象的引用而非对象本身</p>
<h3 id="4-1-1-动态属性-1"><a href="#4-1-1-动态属性-1" class="headerlink" title="4.1.1 动态属性"></a>4.1.1 动态属性</h3><p>利用<code>new</code>创建对象并保存到变量中，可以为这个变量动态添加属性（引用值）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> person = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>person.<span class="hljs-property">name</span> = <span class="hljs-string">&quot;Solace&quot;</span>;<br>person.<span class="hljs-property">age</span> = <span class="hljs-number">19</span>;<br></code></pre></td></tr></table></figure>

<p>原始值不能有属性，只有引用值可以动态添加后面可以使用的属性</p>
<h3 id="4-1-2-复制值-1"><a href="#4-1-2-复制值-1" class="headerlink" title="4.1.2 复制值"></a>4.1.2 复制值</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> num1 = <span class="hljs-number">5</span>;<br><span class="hljs-keyword">let</span> num2 = num1;<br></code></pre></td></tr></table></figure>

<p>原始值复制赋值后两个变量相互独立，互不干扰；</p>
<p>引用值复制的是指针，指向堆内存的对象，两个变量指向同一个对象，改变时两个都变</p>
<img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230824160640062.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230824160640062" style="zoom:50%;" />

<h3 id="4-1-3-传递参数-1"><a href="#4-1-3-传递参数-1" class="headerlink" title="4.1.3 传递参数"></a>4.1.3 传递参数</h3><p>传参（包括对象）只有按值传递，变量有按值和按引用访问</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">setName</span>(<span class="hljs-params">obj</span>) &#123;<br> obj.<span class="hljs-property">name</span> = <span class="hljs-string">&quot;Nicholas&quot;</span>;<br>&#125;<br><span class="hljs-keyword">let</span> person = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br><span class="hljs-title function_">setName</span>(person);<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(person.<span class="hljs-property">name</span>); <span class="hljs-comment">// &quot;Nicholas&quot;</span><br></code></pre></td></tr></table></figure>

<p>再函数内obj和person都指向同一个对象，即使对象是按值传递的obj也会按引用访问该对象</p>
<h3 id="4-1-4-确定类型-1"><a href="#4-1-4-确定类型-1" class="headerlink" title="4.1.4 确定类型"></a>4.1.4 确定类型</h3><p><code>typeof</code>用于原始值</p>
<p>对于引用值使用<code>instanceof</code></p>
<p>用于判断是否为给定引用类型（由其原型链决定，详见第八章）+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(person <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Object</span>); <span class="hljs-comment">// 变量person是Object吗？</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(colors <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>); <span class="hljs-comment">// 变量colors是Array吗？</span><br></code></pre></td></tr></table></figure>

<p>用<code>instanceof</code>检测原始值返回<code>false</code></p>
<h2 id="4-2-执行上下文与作用域-1"><a href="#4-2-执行上下文与作用域-1" class="headerlink" title="4.2 执行上下文与作用域"></a>4.2 执行上下文与作用域</h2><p>执行上下文主要有<strong>全局上下文</strong>和<strong>函数上下文</strong>两种（eval() 调用内部 存在第三种上下文，不常用）</p>
<h5 id="全局执行上下文：-1"><a href="#全局执行上下文：-1" class="headerlink" title="全局执行上下文："></a>全局执行上下文：</h5><p>不在任何函数中的代码都位于全局执行上下文中。</p>
<p>它做了两件事：</p>
<ol>
<li>创建一个全局对象，在浏览器中这个全局对象就是 <code>window</code> 对象。</li>
<li>将 <code>this</code> 指针指向这个全局对象。一个程序中只能存在一个全局执行上下文。</li>
</ol>
<h5 id="函数执行上下文：-1"><a href="#函数执行上下文：-1" class="headerlink" title="函数执行上下文："></a>函数执行上下文：</h5><p>每次调用函数时，都会为该函数创建一个新的执行上下文。并压入执行上下文栈，函数执行结束后从栈中弹出。</p>
<p>每个函数都拥有自己的执行上下文，但是<strong>只有在函数被调用的时候才会被创建</strong>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;aaaaa&quot;</span>;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">check</span>(<span class="hljs-params"></span>) &#123;<br>	<span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;bbbbb&quot;</span>;<br>	<span class="hljs-keyword">function</span> <span class="hljs-title function_">f</span>(<span class="hljs-params"></span>)&#123;<br>		<span class="hljs-keyword">return</span> a;<br>	&#125;<br>	<span class="hljs-keyword">return</span> f;<br>&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">check</span>()());<br><span class="hljs-comment">//global()入栈（全局）</span><br><span class="hljs-comment">//check()入栈</span><br><span class="hljs-comment">//check()出栈</span><br><span class="hljs-comment">//f()入栈</span><br><span class="hljs-comment">//f()出栈</span><br><span class="hljs-comment">//global()出栈</span><br></code></pre></td></tr></table></figure>

<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;aaaaa&quot;</span>;<br><span class="hljs-keyword">function</span> <span class="hljs-title function_">check</span>(<span class="hljs-params"></span>) &#123;<br>	<span class="hljs-keyword">var</span> a = <span class="hljs-string">&quot;bbbbb&quot;</span>;<br>	<span class="hljs-keyword">function</span> <span class="hljs-title function_">f</span>(<span class="hljs-params"></span>)&#123;<br>		<span class="hljs-keyword">return</span> a;<br>	&#125;<br>	<span class="hljs-keyword">return</span> <span class="hljs-title function_">f</span>();<br>&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">check</span>());<br><span class="hljs-comment">//global()入栈（全局）</span><br><span class="hljs-comment">//check()入栈</span><br><span class="hljs-comment">//f()入栈</span><br><span class="hljs-comment">//f()出栈</span><br><span class="hljs-comment">//check()出栈</span><br><span class="hljs-comment">//global()出栈</span><br></code></pre></td></tr></table></figure>

<p>每个上下文都有一个关联的<strong>变量对象</strong>，而这个上下文中定义的所有变量和函数都存在于这个对象上。虽然无法通过代码访问变量对象，但后台处理数据会用到它。</p>
<p>上下文中的代码执行时会创建变量对象的一个<strong>作用域链</strong>，决定了各级上下文中的代码在访问<strong>变量和函数</strong>时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。如果上下文是函数，则其<strong>活动对象</strong>用作变量对象。 活动对象最初只有一个定义变量：arguments 。（全局上下文中没有这个变量。）作用域链中的下一个变量对象来自包含上下文，再下一个对象来自再下一个包含上下文。以此类推直至全局上下文；全局上下文的变量 对象始终是作用域链的最后一个变量对象</p>
<blockquote>
<p>ithink</p>
<p>通过作用域链，JavaScript 引擎可以在当前函数无法找到变量或函数时，依次向上级的变量对象查找，直到找到或者达到全局执行上下文的变量对象。</p>
<p>具体来说，一个函数的变量对象会包含以下内容：</p>
<ol>
<li>函数内部声明的变量，包括通过 <code>var</code>、<code>let</code>、<code>const</code> 声明的变量。</li>
<li>函数声明，即通过函数表达式或函数声明方式定义的函数。</li>
<li>对于非全局函数来说，它的变量对象还会包含指向父级函数的变量对象的引用，以构建作用域链。</li>
</ol>
</blockquote>
<h3 id="4-2-1-作用域链增强-1"><a href="#4-2-1-作用域链增强-1" class="headerlink" title="4.2.1 作用域链增强"></a>4.2.1 作用域链增强</h3><p>某些语句会导致在作用域链前端临时添加一个上下文，这个上下文在代码执行后会被删除。</p>
<ul>
<li><code>try / catch</code>的 <code>catch</code> 块：创建一 个新的变量对象，包含要抛出的错误对象的声明</li>
<li><code>with</code>语句：向作用域链前端添加指定的对象</li>
</ul>
<h3 id="4-2-2-变量声明-1"><a href="#4-2-2-变量声明-1" class="headerlink" title="4.2.2 变量声明"></a>4.2.2 变量声明</h3><h5 id="01-使用var-的函数作用域声明-1"><a href="#01-使用var-的函数作用域声明-1" class="headerlink" title="01. 使用var 的函数作用域声明"></a>01. 使用var 的函数作用域声明</h5><p>使用var 声明变量时，变量会被自动添加到最接近的上下文</p>
<p>变量未经声明就被初始化，会自动被添加到<strong>全局上下文</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">num1, num2</span>) &#123;<br>    <span class="hljs-keyword">var</span> sum = num1 + num2;<br>    <span class="hljs-keyword">return</span> sum;<br>&#125;<br><span class="hljs-keyword">let</span> result = <span class="hljs-title function_">add</span>(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>); <span class="hljs-comment">// 30</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sum); <span class="hljs-comment">// 报错：sum在这里不是有效变量</span><br></code></pre></td></tr></table></figure>

<p>不对sum进行声明后</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">num1, num2</span>) &#123;<br>	sum = num1 + num2;<br>	<span class="hljs-keyword">return</span> sum;<br>&#125;<br><span class="hljs-keyword">let</span> result = <span class="hljs-title function_">add</span>(<span class="hljs-number">10</span>, <span class="hljs-number">20</span>); <span class="hljs-comment">// 30</span><br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(sum); <span class="hljs-comment">// 30，这里sum为全局</span><br></code></pre></td></tr></table></figure>

<p>变量声明提升，但赋值等不变</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name); <span class="hljs-comment">// undefined</span><br><span class="hljs-keyword">var</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br><br><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>	<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name); <span class="hljs-comment">// undefined</span><br>	<span class="hljs-keyword">var</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<h5 id="02-使用let-的块级作用域声明-1"><a href="#02-使用let-的块级作用域声明-1" class="headerlink" title="02. 使用let 的块级作用域声明"></a>02. 使用let 的块级作用域声明</h5><p>单独的块是<code>let</code>声明的作用域；</p>
<p>同一变量名在同一作用域内不能声明两次；</p>
<p><code>var</code>声明的迭代变量会泄露到循环外部，<code>let</code>不会</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; ++i) &#123;&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i); <span class="hljs-comment">// 10</span><br><br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j &lt; <span class="hljs-number">10</span>; ++j) &#123;&#125;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(j); <span class="hljs-comment">// ReferenceError: j没有定义</span><br></code></pre></td></tr></table></figure>

<h5 id="03-使用const-的常量声明-1"><a href="#03-使用const-的常量声明-1" class="headerlink" title="03. 使用const 的常量声明"></a>03. 使用const 的常量声明</h5><p>声明的同时必须初始化；</p>
<p>声明后在其生命周期不能重新赋值，其他同<code>let</code></p>
<p>赋值为对象的 const 变量不能再被重新赋值为其他引用值，但对象的键则不受限制（可以被修改）。</p>
<p><code>Object.freeze()</code>：使整个对象都不能被修改，再给属性赋值时虽然不会报错，但会静默失败：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> o3 = <span class="hljs-title class_">Object</span>.<span class="hljs-title function_">freeze</span>(&#123;&#125;);<br>o3.<span class="hljs-property">name</span> = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(o3.<span class="hljs-property">name</span>); <span class="hljs-comment">// undefined</span><br></code></pre></td></tr></table></figure>

<h5 id="04-标识符查找-1"><a href="#04-标识符查找-1" class="headerlink" title="04. 标识符查找"></a>04. 标识符查找</h5><p>在特定上下文中为了读取或写入而引入一个标识符时，需要在作用域链查找搜索，搜索开始于作用域链前端，搜索给定名称。找到则确定变量，没有找到则沿作用域链查找</p>
<h2 id="4-3-垃圾回收-1"><a href="#4-3-垃圾回收-1" class="headerlink" title="4.3 垃圾回收"></a>4.3 垃圾回收</h2><p>js的执行环境在代码执行时管理内存；</p>
<p><strong>基本思路：</strong>确定哪个变量不会再使用，然后释放它所占用的内存。（周期性：垃圾回收程序每隔一段时间，或在代码执行过程中某个预定的收集时间，就会自动运行）</p>
<p>以函数中局部变量的生命周期为例：</p>
<p>函数执行时，堆（或栈）内存分配空间用于保存相应值，函数在内部使用该变量后退出，此时不再需要这个局部变量，可以释放其占用的内存。</p>
<p>垃圾回收程序跟踪记录哪个变量是否还会使用，以便回收内存</p>
<p>主要两种方法标记未使用的变量：<strong>标记清理</strong>和<strong>引用计数</strong></p>
<h3 id="4-3-1-标记清理-1"><a href="#4-3-1-标记清理-1" class="headerlink" title="4.3.1 标记清理"></a>4.3.1 标记清理</h3><p>最常用</p>
<p>变量进入上下文（如在函数内部声明一个变量）时，这个变量会被加上存在于上下文中的标记。当变量离开上下文时，也会被加上离开上下文的标记。</p>
<p>垃圾回收程序运行时：</p>
<ol>
<li>标记内存中存储的所有变量</li>
<li>去掉所有<code>在上下文中的变量</code>和<code>在上下文中的变量引用的变量</code>的标记</li>
<li>被标记的变量就是待删除变量，销毁带有标记的所有值并收回其内存</li>
</ol>
<p>标记方式：</p>
<ul>
<li>当变量进入上下文时，反转某一位；</li>
<li>维护«<code>在上下文中</code>»和«<code>不在上下文中</code>»两个变量列表，可以把变量从一个列表转移到另一个列表。</li>
</ul>
<h3 id="4-3-2-引用计数-1"><a href="#4-3-2-引用计数-1" class="headerlink" title="4.3.2 引用计数"></a>4.3.2 引用计数</h3><p><strong>思路：</strong>对每个值都记录他被引用的次数，声明变量并赋一个引用值时，该引用值的引用数加一；如果保存对该值引用的变量被其他值覆盖则引用数减一。当一个值的引用数为零时就说明没办法在访问该引用值，可以回收该值的内存。垃圾回收程序下次运行时会释放引用数为零的值的内存</p>
<p><strong>问题：</strong>循环引用</p>
<p>例一：对象A和对象B各有一个指针指向对象B和对象A，A和B通过各自的属性互相引用，引用数都是2。多次调用则有大量内存不会被释放。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">problem</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-keyword">let</span> objectA = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>    <span class="hljs-keyword">let</span> objectB = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>    objectA.<span class="hljs-property">someOtherObject</span> = objectB;<br>    objectB.<span class="hljs-property">anotherObject</span> = objectA;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>例二：在IE8以及更早的IE中，并非所有的对象都是js原生对象。BOM和DOM中的对象是C++实现的组件对象模型（COM） 对象，而COM对象使用<strong>引用计数</strong>实现垃圾回收。即使IE的 JavaScript引擎使用<strong>标记清理</strong>，JavaScript存取的COM对象依旧使用引用计数。也就是说，只要涉及COM对象，就无法避开循环引用问题。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> element = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getElementById</span>(<span class="hljs-string">&quot;some_element&quot;</span>);<br><span class="hljs-keyword">let</span> myObject = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Object</span>();<br>myObject.<span class="hljs-property">element</span> = element;<br>element.<span class="hljs-property">someObject</span> = myObject;<br></code></pre></td></tr></table></figure>

<p>DOM对象和原生js对象发生循环引用，导致即使DOM元素已经被从页面中删除，其内存也不会被回收</p>
<p>解决：确保不使用时切断原生js对象和DOM元素之间的连接</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js">myObject.<span class="hljs-property">element</span> = <span class="hljs-literal">null</span>;<br>element.<span class="hljs-property">someObject</span> = <span class="hljs-literal">null</span>;<br></code></pre></td></tr></table></figure>

<h3 id="4-3-3-性能-1"><a href="#4-3-3-性能-1" class="headerlink" title="4.3.3 性能"></a>4.3.3 性能</h3><p>垃圾回收有可能会明显拖慢渲染的速度和帧速率</p>
<p>IE6机制：根据分配数，如分配了256个变量、4096个对象&#x2F;数组字面量和数组槽位（slot），或64KB字符串。满足其中某个条件垃圾回收程序就会运行。</p>
<p>IE7机制：动态改变触发垃圾回收的阈值，起始阈值与IE6相同，如果回收的内存不到已分配的15%则阈值翻倍；如果有一次的回收内存达到已分配的85%则重置阈值为默认值。</p>
<h3 id="4-3-4-内存管理-1"><a href="#4-3-4-内存管理-1" class="headerlink" title="4.3.4 内存管理"></a>4.3.4 内存管理</h3><p>将内存占用量保持在一个较小的值使页面性能更好（优化内存），数据不在必要时设置为<code>null</code>从而释放引用：<strong>解除引用</strong></p>
<blockquote>
<ul>
<li><p>最适合全局变量和全局对象的属性</p>
<p>局部变量在超出作用域后会自动解除引用</p>
</li>
<li><p>解除引用并不会自动导致相关内存被回收。</p>
<p>解除引用的关键在于确保相关的值已经不在上下文里了，在下次垃圾回 收时会被回收。</p>
</li>
</ul>
</blockquote>
<h5 id="01-通过const-和let-声明提升性能-1"><a href="#01-通过const-和let-声明提升性能-1" class="headerlink" title="01. 通过const 和let 声明提升性能"></a>01. 通过const 和let 声明提升性能</h5><p>都以块为作用域而不是函数，可能会更早地让垃圾回收程序介入，尽早回收</p>
<h5 id="02-隐藏类和删除操作-1"><a href="#02-隐藏类和删除操作-1" class="headerlink" title="02. 隐藏类和删除操作"></a>02. 隐藏类和删除操作</h5><p><img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831232900624.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230831232900624"></p>
<p><img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234032078.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230831234032078"></p>
<p><img src="C:\Users\28408\AppData\Roaming\Typora\typora-user-images\image-20230831234111148.png" srcset="/blog/img/loading.gif" lazyload alt="image-20230831234111148"></p>
<h5 id="03-内存泄露-1"><a href="#03-内存泄露-1" class="headerlink" title="03. 内存泄露"></a>03. 内存泄露</h5><p><strong>问题一</strong>：意外声明全局变量，未给变量利用<code>var</code>，<code>let</code>，<code>const</code>声明会被默认当做<code>window</code>属性来创建</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">setName</span>(<span class="hljs-params"></span>) &#123;<br> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br>&#125;<br><span class="hljs-comment">//相当于window.name = &#x27;Jake&#x27;</span><br></code></pre></td></tr></table></figure>

<p>解决：加上声明</p>
<p><strong>问题二</strong>：定时器</p>
<p>例中定时器的回调通过闭包引用了外部变量</p>
<p>只要定时器一直运行，回调函数中引用的name 就会一直占用内存。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br><span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> &#123;<br> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(name);<br>&#125;, <span class="hljs-number">100</span>);<br></code></pre></td></tr></table></figure>

<p><strong>问题三：</strong>闭包</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">let</span> outer = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>    <span class="hljs-keyword">let</span> name = <span class="hljs-string">&#x27;Jake&#x27;</span>;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) &#123;<br>    	<span class="hljs-keyword">return</span> name;<br>    &#125;;<br>&#125;;<br></code></pre></td></tr></table></figure>

<p>调用<code>outer()</code>会导致分配给name的内存被泄漏，只要返回的函数存在就不能清理name ，因为闭包一直在引用着它</p>
<h5 id="04-静态分配与对象池-1"><a href="#04-静态分配与对象池-1" class="headerlink" title="04. 静态分配与对象池"></a>04. 静态分配与对象池</h5><p>为了提升性能，应当减少浏览器执行垃圾回收的次数 $\to$ 合理使用分配的内存，同时避免多余的垃圾回收，可以保住因释放内存而损失的性能</p>
<p>浏览器决定何时运行垃圾回收程序的一个标准就是对象更替的速度</p>
<p>例：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">addVector</span>(<span class="hljs-params">a, b</span>) &#123;<br>    <span class="hljs-keyword">let</span> resultant = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Vector</span>();<br>    resultant.<span class="hljs-property">x</span> = a.<span class="hljs-property">x</span> + b.<span class="hljs-property">x</span>;<br>    resultant.<span class="hljs-property">y</span> = a.<span class="hljs-property">y</span> + b.<span class="hljs-property">y</span>;<br>    <span class="hljs-keyword">return</span> resultant;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>如果矢量对象的生命周期很短 $\to$ 很快会成为可以被回收的值，如果频繁调用函数 $\to$ 垃圾回收程序会发现这里对象更替速度很快 $\to$ 更频繁的安排垃圾回收</p>
<p>解决：不使用动态创建对象，比如将对象通过传参传入</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">addVector</span>(<span class="hljs-params">a, b, resultant</span>) &#123;<br>    resultant.<span class="hljs-property">x</span> = a.<span class="hljs-property">x</span> + b.<span class="hljs-property">x</span>;<br>    resultant.<span class="hljs-property">y</span> = a.<span class="hljs-property">y</span> + b.<span class="hljs-property">y</span>;<br>    <span class="hljs-keyword">return</span> resultant;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>在<strong>对象池</strong>中创建对象可以不让垃圾回收程序盯上，用于管理一组可回收的对象。</p>
<p>程序可以向对象池请求一个对象并设置属性，在使用结束后还给对象池</p>
<p>由于没有对象初始化，垃圾回收程序不会发现对象更替，减少垃圾回收程序执行频率</p>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/blog/tags/Javascript/" class="print-no-link">#Javascript</a>
      
        <a href="/blog/tags/%E7%BA%A2%E5%AE%9D%E4%B9%A6/" class="print-no-link">#红宝书</a>
      
        <a href="/blog/tags/web/" class="print-no-link">#web</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>JS红宝书第四章学习笔记</div>
      <div>https://isolace.gitee.io/blog/2023/11/17/JS红宝书第四章学习笔记/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>Solace</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2023年11月17日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a class="print-no-link" target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/blog/2024/03/26/%E8%93%9D%E6%A1%A5%E6%9D%AFweb%E7%BB%84%E8%80%83%E7%82%B9/" title="蓝桥杯web组考点">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">蓝桥杯web组考点</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/blog/2023/11/15/JS%E7%BA%A2%E5%AE%9D%E4%B9%A6%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" title="JS红宝书第三章学习笔记">
                        <span class="hidden-mobile">JS红宝书第三章学习笔记</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
  
  
    <article id="comments" lazyload>
      
  <div id="twikoo"></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#comments', function() {
      Fluid.utils.createScript('https://lib.baomitu.com/twikoo/1.6.8/twikoo.all.min.js', function() {
        var options = Object.assign(
          {"envId":"https://imaginative-rabanadas-4bf3ac.netlify.app/.netlify/functions/twikoo","region":"AWS / N. Virginia (us-east-1)","path":"window.location.pathname"},
          {
            el: '#twikoo',
            path: 'window.location.pathname',
            onCommentLoaded: function() {
              Fluid.utils.listenDOMLoaded(function() {
                var imgSelector = '#twikoo .tk-content img:not(.tk-owo-emotion)';
                Fluid.plugins.imageCaption(imgSelector);
                Fluid.plugins.fancyBox(imgSelector);
              });
            }
          }
        )
        twikoo.init(options)
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


    </article>
  


          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>
  </div>
</div>





  



  



  



  



  


  
  









    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <span>Solace</span><br> <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
    </div>
  
  
    <div class="statistics">
  
  

  
    
      <span id="busuanzi_container_site_pv" style="display: none">
        总访问量 
        <span id="busuanzi_value_site_pv"></span>
         次
      </span>
    
    
      <span id="busuanzi_container_site_uv" style="display: none">
        总访客数 
        <span id="busuanzi_value_site_uv"></span>
         人
      </span>
    
    
  
</div>

  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.4/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/blog/js/events.js" ></script>
<script  src="/blog/js/plugins.js" ></script>





  
    <script  src="/blog/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.20.1/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  
      <script>
        if (!window.MathJax) {
          window.MathJax = {
            tex    : {
              inlineMath: { '[+]': [['$', '$']] }
            },
            loader : {
              load: ['ui/lazy']
            },
            options: {
              renderActions: {
                insertedScript: [200, () => {
                  document.querySelectorAll('mjx-container').forEach(node => {
                    let target = node.parentNode;
                    if (target.nodeName.toLowerCase() === 'li') {
                      target.parentNode.classList.add('has-jax');
                    }
                  });
                }, '', false]
              }
            }
          };
        } else {
          MathJax.startup.document.state(0);
          MathJax.texReset();
          MathJax.typeset();
          MathJax.typesetPromise();
        }

        Fluid.events.registerRefreshCallback(function() {
          if ('MathJax' in window && MathJax.startup.document && typeof MathJax.startup.document.state === 'function') {
            MathJax.startup.document.state(0);
            MathJax.texReset();
            MathJax.typeset();
            MathJax.typesetPromise();
          }
        });
      </script>
    

  <script  src="https://lib.baomitu.com/mathjax/3.2.2/es5/tex-mml-chtml.js" ></script>

  <script  src="/blog/js/local-search.js" ></script>

  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/blog/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
